﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Wheels
{
    public static class PathUtility
    {
        private enum FoundSeparator
        {
            None,
            ForwardSlash,
            BackSlash,
        }

        // placeholder
        [Obsolete("Don't use until fixed.", true)]
        public static string CombinePath(this string path, params string[] otherPaths)
        {
            throw new NotImplementedException();
        }

        // TODO: 此实现可能需要重新验证
        [Obsolete("Don't used until tested.")]
        public static string CombinePath(this string path, char separator, params string[] otherPaths)
        {
            var noAnotherSeparator = path.IsNullOrEmpty() || path[path.Length - 1] == separator;

            //var strSeparator = separator.ToString();
            var root = path.GetPathRoot(separator);

            var gaugeLength = path.Length + otherPaths.Sum(s => s.Length) + otherPaths.Length;
            var sb = new StringBuilder(gaugeLength);
            sb.Append(path);

            foreach (var s in otherPaths)
            {
                var part = s;

                if (!noAnotherSeparator)
                    sb.Append(separator);

                if (part.IsNullOrEmpty())
                {
                    noAnotherSeparator = true;
                    continue;
                }

                //if (part[0] == '.')
                //{
                //  if (part.Length > 1)
                //  {
                //    if (part[1] == separator)
                //    {
                //      part = part.Substring(2);
                //    }
                //    // TODO: 修正包含上级目录符号时的行为
                //    else if (part[1] == '.')
                //    {
                //      if (part.Length == 2 || (part.Length > 2 && part[2] == separator))
                //      {
                //        var pathParent = sb.ToString().GetPathParent(separator);
                //        sb.Clear();
                //        sb.Append(pathParent);


                //        part = part.Length == 2 ? "" : part.Substring(3);
                //      }
                //    }
                //  }
                //  else
                //  {
                //    noAnotherSeparator = true;
                //    continue;
                //  }
                //}
                //else
                //{
                var thisRoot = part.GetPathRoot(separator);
                if (thisRoot != null)
                {
                    root = thisRoot;
                    sb.Clear();
                }
                else if (part[0] == separator)
                {
                    sb.Clear();
                    sb.Append(root);
                }
                //}

                sb.Append(part);
                noAnotherSeparator = part.IsNullOrEmpty() || part[part.Length - 1] == separator;
            }

            return sb.ToString();
        }

        /// <summary>
        /// 提取指定路径的亲代路径，维持已有的目录分隔符。
        /// </summary>
        /// <param name="path"></param>
        /// <param name="separator"></param>
        public static string GetPathParent(this string path, char separator)
        {
            if (path == null)
                return null;

            var strSeparator = separator.ToString();
            var parentStart = ".." + strSeparator;

            // 第一个例外状况，传入空白字符串
            if (path == "")
                return parentStart;

            //var parentEnd = strSeparator + "..";
            var path2 = path;

            // 第二个例外状况，传入的路径仅代表上级目录
            if (".." == path2)
                return parentStart + parentStart;

            // 已知路径以表示上级目录的符号起始
            if (path2.StartsWith(parentStart, StringComparison.Ordinal))
                return path2.AppendTrailingDirectorySeparator(separator) + parentStart;

            // 从根路径之后开始分析路径组成部分
            var root = path2.GetPathRoot(separator);
            if (root != null)
            {
                path2 = path2.Substring(root.Length);
            }

            path2 = path2.RemoveTrailingDirectorySeparator(separator);

            var i = path2.Length;
            while (i-- > 0)
            {
                // 寻找路径中最后一个表示目录名的部分，若为“..”的形式则直接在其后添加表示上级目录的符号
                if (path2[i] == separator)
                {
                    if (path2.Substring(i + 1) == "..")
                        return path.AppendTrailingDirectorySeparator(separator) + parentStart;

                    return root + path2.Substring(0, i + 1);
                }
            }

            // 如果到此处没有找到任何有用的信息，就只能返回空白了
            if (root == null)
                return "";

            // root 的内容被规范为永远不以目录分隔符结尾，所以此处需要补充
            return root + strSeparator;
        }

        /// <summary>
        /// 提取指定路径的根，去除末尾的目录分隔符。
        /// </summary>
        /// <param name="path"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static string GetPathRoot(this string path, char separator)
        {
            return path.GetPathRoot(separator, ':');
        }
        // TODO: 此实现可能需要重新验证
        private static string GetPathRoot(this string path, char separator, char driveMark)
        {
            if (path.IsNullOrEmpty())
                return null;

            if (path[0] == separator)
            {
                var hasRootName =
                  path.Length > 2 &&
                  (path[1] == separator || // this is for "//(host)/...", "//?/..."
                  (path[1] == '?' && // and this is for "/??/..."
                  path[2] == '?'));

                if (hasRootName)
                {
                    var len = path.IndexOf(separator, 2);
                    if (len < 0)
                        return path;

                    return path.Substring(0, len);
                }
                else
                {
                    return separator.ToString();
                }
            }
            else
            {
                var hasRootName =
                  path.Length > 1 &&
                  path[1] == driveMark &&
                  (path.Length == 2 || // "X:" 
                  path[2] == separator); // "X:\..."

                if (hasRootName)
                    return path.Substring(0, 2);
            }

            return null;
        }

        /// <summary>
        /// 向路径字符串末尾补充经由严谨算法得出的目录分隔符，此算法会验证路径中是否混用了不同种类的目录分隔符。
        /// </summary>
        public static string AppendTrailingDirectorySeparator(this string path)
        {
            if (path.IsNullOrEmpty())
                return path;

            var found = FoundSeparator.None;
            var endsWithSeparator = true; // who cares!?

            foreach (var c in path)
            {
                switch (c)
                {
                    case '/':
                        switch (found)
                        {
                            case FoundSeparator.None:
                                found = FoundSeparator.ForwardSlash;
                                break;
                            case FoundSeparator.ForwardSlash:
                                break;
                            default:
                                throw new ArgumentOutOfRangeException();
                        }

                        endsWithSeparator = true;
                        break;
                    case '\\':
                        switch (found)
                        {
                            case FoundSeparator.None:
                                found = FoundSeparator.BackSlash;
                                break;
                            case FoundSeparator.BackSlash:
                                break;
                            default:
                                throw new ArgumentOutOfRangeException();
                        }

                        endsWithSeparator = true;
                        break;

                    default:
                        endsWithSeparator = false;
                        break;
                }
            }

            if (endsWithSeparator)
                return path;

            switch (found)
            {
                case FoundSeparator.ForwardSlash:
                    return path + "/";

                case FoundSeparator.BackSlash:
                    return path + "\\";

                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        /// <summary>
        /// 向路径字符串末尾补充指定的目录分隔符。
        /// </summary>
        /// <param name="path"></param>
        /// <param name="separator"></param>
        public static string AppendTrailingDirectorySeparator(this string path, char separator)
        {
            if (path.IsNullOrEmpty())
                return path;

            if (path[path.Length - 1] == separator)
                return path;

            return path + separator.ToString();
        }

        /// <summary>
        /// 采用较为宽松的算法去除路径字符串末尾的目录分隔符，此算法仅验证路径末尾是否混用了不同种类的目录分隔符。
        /// </summary>
        public static string RemoveTrailingDirectorySeparatorRelaxed(this string path)
        {
            if (path.IsNullOrEmpty())
                return path;

            var found = FoundSeparator.None;

            var i = path.Length;
            while (i-- > 0)
            {
                var c = path[i];

                switch (c)
                {
                    case '/':
                        switch (found)
                        {
                            case FoundSeparator.None:
                                found = FoundSeparator.ForwardSlash;
                                break;
                            case FoundSeparator.ForwardSlash:
                                break;
                            default:
                                throw new ArgumentOutOfRangeException();
                        }
                        break;
                    case '\\':
                        switch (found)
                        {
                            case FoundSeparator.None:
                                found = FoundSeparator.BackSlash;
                                break;
                            case FoundSeparator.BackSlash:
                                break;
                            default:
                                throw new ArgumentOutOfRangeException();
                        }
                        break;

                    default:
                        return path.Substring(0, i + 1);
                }
            }

            return "";
        }

        /// <summary>
        /// 采用较为严谨的算法去除路径字符串末尾的目录分隔符，此算法验证整个路径是否混用了不同种类的目录分隔符。
        /// </summary>
        public static string RemoveTrailingDirectorySeparator(this string path)
        {
            if (path.IsNullOrEmpty())
                return path;

            var found = FoundSeparator.None;
            var lastValidCharPos = -1;

            for (var i = 0; i < path.Length; i++)
            {
                var c = path[i];

                switch (c)
                {
                    case '/':
                        switch (found)
                        {
                            case FoundSeparator.None:
                                found = FoundSeparator.ForwardSlash;
                                break;
                            case FoundSeparator.ForwardSlash:
                                break;
                            default:
                                throw new ArgumentOutOfRangeException();
                        }
                        break;
                    case '\\':
                        switch (found)
                        {
                            case FoundSeparator.None:
                                found = FoundSeparator.BackSlash;
                                break;
                            case FoundSeparator.BackSlash:
                                break;
                            default:
                                throw new ArgumentOutOfRangeException();
                        }
                        break;

                    default:
                        lastValidCharPos = i;
                        break;
                }
            }

            return path.Substring(0, lastValidCharPos + 1);
        }

        /// <summary>
        /// 若路径字符串以指定的目录分隔符结尾，则去除此目录分隔符。
        /// </summary>
        /// <param name="path"></param>
        /// <param name="separator"></param>
        public static string RemoveTrailingDirectorySeparator(this string path, char separator)
        {
            if (path.IsNullOrEmpty())
                return path;

            var i = path.Length;
            while (i-- > 0)
            {
                if (path[i] != separator)
                    return path.Substring(0, i + 1);
            }

            return path;
        }
    }
}
